'use strict';
app.controller('datatableCtrl', ['$scope', '$modal', '$rootScope', '$http', '$filter', '$stateParams', '$timeout', 'lodash','$location', function ($scope, $modal, $rootScope, $http, $filter, $stateParams, $timeout, lodash,$location) {
    $rootScope.initBreadcrumb($scope.breadcrumb);
    //页面加载时，给headerElement设置元素
    $rootScope.initHeaderElements($scope.settings);
    var saveBtn = {
        show: true,
        label: '保存',
        func: function () {
            // updateFlowDetails();
            updateFlowDetails2();
        }
    };
    var backUrl = {
        show: true,
        label: "返回",
        func: function () {
            $rootScope.backHistory();
        }
    };
    var  jumpUrl = {
        show: true,
        label: "流程架构",
        func: function () {
            window.open('#/app/repository/flow/');
        }
    };

    $scope.settings.btnEle.push(saveBtn);
    $scope.settings.btnEle.push(backUrl); 
    if($rootScope.isMatrixCusRole('matrix_sys_admin')){
       $scope.settings.btnEle.push(jumpUrl);
    }
    //结束headerElement设置

    $scope.reqDetails = {};
    $scope.info = {
        addNum         : 0,   //记录点击添加的次数，用户给新创建的图例定位
        currentReqId   : $stateParams.reqId ? $stateParams.reqId : "-1",
        statusList     : config_flow_node_status,
        flowTypeArray  : [{"crtname": "功能点", "type": "feature"}, {"crtname": "流程", "type": "flow"}],
        diagramStatus  : "current",
        sltStatusItem  : "",
        nameAndVersion : "",
        relateFeatures : [],    //req关联的feature数据
        flowData       : [],    //流程结构数据集合
        flowTree       : [],    //流程数据集合
        my_tree        : {},
        isFeature      : true,
        isDisabled     : true,
        viewStatus     : "current",
        flowArray      : [],
        selectedFlow   : {},     //当前选中的节点对象
        input          : "",     //输入内容（查询画板中的流程节点）
        selectValue    : "1",    //已有节点下拉框的选中值
        flowId         : "",     //更新时所需的flowId
        flowDetails    : {},     //点击的流程详细数据
        legendList     : [],     //点击flow时获取图例列表
        featureList    : [],     //全部功能点
        reqFlows       : [],     //req关联的流程列表
        reqRelateFlows : [],     //req关联的列表（状态为ADD，UPDATE）
        reqNodeFlows   : [],     //req关联的流程（状态为NODE_UPDATE）
        featureDisabled: true,   //默认不可点击
        diagram        : null,
        jumpToFeature  : null,   //跳转到的featureId
        hasRelate      : false,  //是否被关联   true：是   false：否
        removeFinished : false,  //删除后，树上的按钮是否显示 true: 显示  false: 否
        currentDiagram : true,   //req不为-1时，显示当前diagram
        masterDiagram  : false,  //req为-1时，显示master的diagram
        nodeDataArray  : [],
        linkDataArray  : [],
        customLegendArray: [
            {feature_lengend_id: "c01", category: "Start", text: "开始"},
            {feature_lengend_id: "c02", category: "Next", text: "下一步"},
            {feature_lengend_id: "c03", category: "Diamond", text: "判断", figure: "Diamond"},
            {feature_lengend_id: "c04", category: "End", text: "结束"},
            {feature_lengend_id: "c05", category: "Comment", text: "描述"},
            {feature_lengend_id: "c06", category: "Line", text: "线","length":50},
            {feature_lengend_id: "c08", category: "vLine", text: "竖线","length":50},
            {feature_lengend_id: "c07", category: "User", text: "用户"},
        ],
        customFeatureArray: [],
        sltLegendItem: "",   //选择的图例数据
        reqFlowDatas: {},
        masterFlowDatas: {},
        diagramScope: {}
    };
    
    //定义节点数据和节点线数据
    $scope.info.model = new go.GraphLinksModel([], []);
    $scope.info.modelMaster = new go.GraphLinksModel([], []);
    $scope.info.model.selectedFlowData = null;
    $scope.info.modelMaster.selectedFlowData = null;
    $scope.info.mDiagram = null;   //设置画布只读时需要
    $scope.info.mDiagramMaster = null;   //设置画布只读时需要
    //定义节点工具框内容
    $scope.info.paModel = new go.GraphLinksModel($scope.info.customLegendArray);
    $scope.info.paModelMaster = new go.GraphLinksModel($scope.info.customLegendArray);

    getFlowTree();
    setDesignTabName();

    $timeout(function() {
        setFlowHeight();
    })

    function setFlowHeight() {
        $("#flow-builder-content").css("height", (window.screen.availHeight-140)+"px");
    }

    //获取产品设计名称
    function setDesignTabName() {
        var url = matrix_product_url +"/brdRequirement/getBrdRequirements?reqId="+ $stateParams.reqId;
        $http.get(url).success(function(result) {
            if(result.code == "0") {
                if(result.data) {
                    $scope.reqDetails = result.data[0];
                    $scope.breadcrumb.push('产品设计',$scope.reqDetails.reqName);
                }
            }
        });
    }

    //获取流程树
    function getFlowTree() {
        var url = matrix_product_url + "/flow/getFlowTree";
        $http.get(url).success(function (result) {
            if (result.code == "0") {
                $scope.info.flowTree = result.data.children;
                $scope.info.flowArray = setFlowLegendPath(result.data.children, [], "");
                setDiagramReadonly(true);
                getReqFlows($scope.info.currentReqId);
                getReqRelateFeature();
                $timeout(function() {
                    var firstBranch = lodash.first($scope.info.flowTree);
                    $scope.info.my_tree.set_select_branch_by_id(firstBranch.id);
                }, 500);
            } else {
                $rootScope.toasterErrorInfo(result.desc);
            }
        });
    };

    //解析流程树数据
    function setFlowLegendPath(featureTree, resultFeatureArray, featureName) {
        angular.forEach(featureTree, function (feature, index) {
            var pathUrl = featureName ? featureName + "/" + feature.name : feature.name;
            //type  1: frame   2: flow
            if(feature.type == "2") {
                var featureItem = {
                    crtname: pathUrl,
                    category: "formula",
                    text: pathUrl ? "P: "+ lodash.last(pathUrl.split("/")) : "",
                    nodeType: "flow",
                    //feature_id: feature.id,
                    //isHighlighted: feature.status ? (feature.status == "ADD" ? true : false) : false,
                    isHighlighted: "flow",
                    feature_info: {
                        id: feature.id,
                        sys: "",
                        type: feature.type,
                        title: pathUrl ? pathUrl : "",
                        status: feature.status ? feature.status : "ADD",
                        relate_id: "",
                        relate_type: "",
                        relate_name: lodash.last(pathUrl.split("/")),
                        relate_path: pathUrl,
                        bussiness_line_id: feature.metaData.bussinessId,
                    },
                    status: feature.status ? feature.status : "ADD",
                    sys: "",
                    relate_name: lodash.last(pathUrl.split("/")),
                    relate_path: pathUrl,
                }
                resultFeatureArray.push(featureItem);
            }
            if (feature.children && feature.children.length) {
                setFlowLegendPath(feature.children, resultFeatureArray, feature.name);
            }
        });
        return resultFeatureArray;
    };

    //点击树获取节点信息
    $scope.my_tree_handler = function (branch) {
        console.log("----查看流程节点数据----");
        console.log(branch);
        $scope.info.selectedFlow = branch;
        $scope.info.sltLegendItem = "";
        $scope.info.legendList = [];
        $scope.info.removeFinished = false;
        if (branch.type == "2") {   //判断是否为flow节点（1： frame节点 2：flow节点）
            $scope.info.isDisabled = false;
            $scope.info.addNum = 0;
            //getFlowDetailsOfLegend(branch.id, "2");
            getFeatureList();
            var isRelateFlow = lodash.findWhere($scope.info.reqFlows, {id: branch.id});
            if(isRelateFlow == undefined) {    //isRelateFlow undefined: 未被关联   
                setDiagramMasterReadonly(true);
                $scope.info.viewStatus = "online";
                $scope.info.diagramStatus = "online";
                $scope.info.isDisabled = true;
                $scope.info.jumpToFeature = "";
                getFlowDetailsOfNode(branch.id, "-1");
            } else {
                setDiagramReadonly(false);
                $scope.info.viewStatus = "current";
                $scope.info.diagramStatus = "current";
                $scope.info.jumpToFeature = branch.id;
                getFlowDetailsOfNode(branch.id, $scope.info.currentReqId);
            }
        } else {
            $scope.info.isDisabled = true;
            $scope.info.jumpToFeature = "";
            setDiagramReadonly(true);
            //getFlowDetailsOfLegend(branch.id, "1");
            //frame节点，初始化画布为空
            $scope.info.model = new go.GraphLinksModel([], []);
        }
    };

    //设置画布是否只读
    function setDiagramReadonly(status) {
        // $scope.info.mDiagram.setProperties({
        //     isReadOnly: status
        // });
    };

    //设置master画布是否只读
    function setDiagramMasterReadonly(status) {
        // $scope.info.mDiagramMaster.setProperties({
        //     isReadOnly: status
        // });
    }

    //获取全部的功能点（用于选择功能点然后添加到流程图模板组件中）
    function getFeatureList() {
        var url = matrix_product_url +"/feature/getFeature?withPrototype=1&withAttr=0";
        $http.get(url).success(function(result) {
            if(result.code == "0") {
                $scope.info.featureDisabled = false;
                var featureList = [];
                angular.forEach(result.data, function(res, index) {
                    if(res.path) {                        
                        var itemName = res.type == "PROTOTYPE" ? res.featureName+"【"+ lodash.last(res.path.split("/")) +"】" : res.featureName;
                        var item = {
                            crtname: "..." + res.path.substring(17),
                            category: "formula",
                            text: res.path ? "F: "+ itemName : "F: "+lodash.last(res.path.split("/")),
                            feature_id: res.id,
                            nodeType: "feature",
                            //isHighlighted: res.status ? (res.status == "ADD" ? true : false) : false,
                            isHighlighted: "",
                            feature_info: {
                                id: res.id,
                                sys: res.sys,
                                type: res.type,
                                title: res.featureName ? itemName : "",
                                status: res.status ? res.status : "ADD",
                                relate_id: "",
                                relate_type: "",
                                relate_name: (res.type == "PROTOTYPE" ? lodash.last(res.path.split("/")) : res.featureName),
                                relate_path: res.path,
                                bussiness_line_id: res.bussinessLine,
                            },
                            status: res.status ? res.status : "ADD",
                            sys: res.sys,
                            relate_name: (res.type == "PROTOTYPE" ? lodash.last(res.path.split("/")) : res.featureName),
                            relate_path: res.path,
                        }
                        // resultLegendArray.push(item);
                        featureList.push(item);
                    }
                });
                $scope.info.featureList = featureList;
                //var orderByLegend = $filter('orderBy')(resultLegendArray, "index", false);
                //$scope.info.paModel = new go.GraphLinksModel(orderByLegend);
            } else {
                $rootScope.toasterErrorInfo(result.desc);
            }
        });
    };

    //获取flow的节点详细信息
    function getFlowDetailsOfNode(flowId, reqId) {
        $scope.showFlowBuilder = false;
        var url = matrix_product_url +"/flow/getFlowDetail?flowId="+ flowId +"&reqId="+ reqId;
        $http.get(url).success(function (result) {
            if (result.code == "0") {
                if (!result.data) {
                    $rootScope.toasterErrorInfo("获取流程信息错误！");
                    return false;
                }
                
                console.log("+++++++++++++++++++++++++++++++");
                console.log(result.data.attrs);
                if(reqId == "-1") {
                    $scope.info.masterFlowDatas = {"nodeDataArray": result.data.attrs.nodeDataArray || [{ "key":1, "text":"Start", "category":"Start" }], "linkDataArray": result.data.attrs.linkDataArray || []};
                } else {
                    $scope.info.reqFlowDatas = {"nodeDataArray": result.data.attrs.nodeDataArray || [{ "key":1, "text":"Start", "category":"Start" }], "linkDataArray": result.data.attrs.linkDataArray || []};
                }


                $scope.info.hasRelate = lodash.findWhere($scope.info.reqFlows, {id: result.data.id});
                $scope.info.flowId = result.data.id;
                $scope.info.flowDetails = result.data;
                $scope.info.nameAndVersion = {"name": result.data.name, "version": "v"+(result.data.attrs != null ? result.data.attrs.version : "")};
                if (!result.data.attrs) {
                    $scope.info.model = new go.GraphLinksModel([], []);
                    return false;
                }
                angular.forEach(result.data.attrs.nodeDataArray, function(node) {
                    var reqRelateIndex = lodash.findIndex($scope.info.relateFeatures, function(feature) {
                        return feature.id == node.feature_id;
                    });
                    if(reqRelateIndex != -1) {
                        node.isHighlighted = "isRelate";
                    } else {
                        node.isHighlighted = node.nodeStatus == "ADD" ? "ADD" : "";
                    }
                    if(node.nodeType == "flow") {
                        node.isHighlighted = "flow";
                    }
                });
                $scope.info.nodeDataArray = result.data.attrs.nodeDataArray;
                $scope.info.linkDataArray = result.data.attrs.linkDataArray;
                switch($scope.info.diagramStatus) {
                    case "current":
                        $scope.info.currentDiagram = true;
                        $scope.info.masterDiagram = false;
                        setDiagramReadonly(false);
                        break;
                    case "online":
                        $scope.info.currentDiagram = false;
                        $scope.info.masterDiagram = true;
                        setDiagramMasterReadonly(true);
                        break;
                    case "compare":
                        $scope.info.currentDiagram = true;
                        $scope.info.masterDiagram = true;
                        reqId == "-1" ? setDiagramMasterReadonly(true) : setDiagramReadonly(true);
                        break;
                }
            } else {
                $rootScope.toasterErrorInfo(result.desc);
            }
            $scope.showFlowBuilder = true;
        });
    };

    //获取当前req关联的功能点数据
    function getReqRelateFeature() {
        var url = matrix_product_url +"/feature/getAllFeatureForReq?reqId="+ $scope.info.currentReqId;
        $http.get(url).success(function(result) {
            if(result.code == "0") {
                $scope.info.relateFeatures = result.data ? result.data : [];
            } else {
                $rootScope.toasterErrorInfo(result.desc);
            }
        });
    };

    //更新flow节点的详细信息（更新flow的attrs）
    function updateFlowDetails() {
        var isRelateFlow = lodash.findWhere($scope.info.reqFlows, {id: $scope.info.selectedFlow.id});
        if(isRelateFlow == undefined) {
            return false;
        }
        var nodeArray = $scope.info.model.nodeDataArray;
        var linkArray = $scope.info.model.linkDataArray;
        var nodeDataArray = $scope.info.nodeDataArray;
        var linkDataArray = $scope.info.linkDataArray;
        var currentDate = Number(new Date());
        var postParams = {
            reqId: $stateParams.reqId ? $stateParams.reqId : "-1",
            flowId: $scope.info.flowId, 
            attrs: {
                "date": currentDate,
                "version": $scope.info.flowDetails.attrs.version,
                "req_snapshot": $scope.info.flowDetails.attrs.req_snapshot,
                "master_version": $scope.info.flowDetails.attrs.master_version,
                "nodeDataArray": nodeDataArray ? nodeDataArray : nodeArray,
                "linkDataArray": linkDataArray ? linkDataArray : linkArray,
            }
        };
        console.log(JSON.stringify(preventCircularJson(postParams)));
        var url = matrix_product_url + "/flow/updateReqFlowContent";
        $http({
            method: "post",
            url: url,
            data: JSON.stringify(postParams),
            headers: {"Content-Type": "application/json"}
        }).success(function (result) {
            if (result.code == "0") {
                $rootScope.toasterSuccessInfo("保存成功！");
            } else {
                $rootScope.toasterErrorInfo(result.desc);
            }
        });
    };

    //解决转换json时的bug
    function preventCircularJson(source, censoredMessage, censorTheseItems) {
        censorTheseItems = censorTheseItems || [source];
        censoredMessage = censoredMessage || "CIRCULAR_REFERENCE_REMOVED";
        var recursiveItems = {};
        var ret = {};
        for (var key in source) {
            var value = source[key]
            if (typeof value == "object") {
                recursiveItems[key] = value;
            } else {
                ret[key] = value;
            }
        }
        var censorChildItems = [];
        for (var key in recursiveItems) {
            var value = source[key];
            censorChildItems.push(value);
        }
        for (var key in recursiveItems) {
            var value = source[key];
            var censored = false;
            censorTheseItems.forEach(function (item) {
                if (item === value) {
                    censored = true;
                }
            });
            if (censored) {
                value = censoredMessage;
            } else {
                value = preventCircularJson(value, censoredMessage, censorChildItems.concat(censorTheseItems));
            }
            ret[key] = value
        }
        return ret;
    }

    //添加流程方法
    $scope.addFlow = function () {
        openFlowModal("add", "", "");
    };

    //编辑流程
    $scope.editFlow = function () {
        $scope.info.reqNodeFlows = [];
        $scope.info.reqRelateFlows = [];
        openFlowModal("edit", $scope.info.selectedFlow, "");
    };

    //复制流程
    $scope.copyFlow = function () {
        openFlowModal("copy", $scope.info.selectedFlow, $scope.info.flowDetails);
    };

    //打开流程模态框
    function openFlowModal(type, defaultValue, flowDetails) {
        if (!$scope.info.selectedFlow) {
            $rootScope.toasterWarningInfo("请先选择流程！");
            return false;
        }
        var modalInstance = $modal.open({
            animation: true,
            templateUrl: getTemplateUrl("matrix/component/tpl/flowNodeModal.html"),
            controller: "editFlowCtrl",
            keyboard: true,
            backdrop: true,
            resolve: {
                type: function () {
                    return type;
                },
                defaultValue: function () {
                    return defaultValue;
                },
                flowDetails: function () {
                    return flowDetails;
                }
            }
        });

        modalInstance.result.then(function (flowName) {
            editFlowDetails(flowName);
        }, function (reason) {
            console.log("关闭modal");
        });
    };

    //编辑流程（创建，修改，复制）
    function editFlowDetails(flowData) {
        var url = matrix_product_url +(flowData.type != "edit" ? "/flow/createFlow" : "/flow/updateMasterFlow");

        var flowDetails = $scope.info.selectedFlow;
        var postParams = {
            name: flowData.name,
            reqId: $stateParams.reqId ? $stateParams.reqId : "-1",
        };
        if (flowData.type == "add") {
            postParams.bussinessId = flowDetails.id
        }
        if (flowData.type == "edit") {
            postParams.id = flowDetails.id
        }
        if (flowData.type == "copy") {
            postParams.bussinessId = flowData.id;
            postParams.attrs = flowData.attrs;
        }
        $http({
            method: "post",
            url: url,
            data: JSON.stringify(postParams),
            headers: {"Content-Type": "application/json"}
        }).success(function (result) {
            if (result.code == "0") {
                if (flowData.type != "edit") {
                    var flowItem = {
                        id: result.data.id,
                        name: result.data.name,
                        parentId: result.data.bussinessId,
                        type: "2",
                        level: parseInt($scope.info.selectedFlow.level) + 1,
                        isDel: "1",
                        children: [],
                        metaData: result.data
                    };
                    if (flowData.type == "add") {
                        if (!$scope.info.selectedFlow.children.length) {
                            $scope.info.selectedFlow.children = [];
                        }
                        flowItem.status = "ADD";
                        $scope.info.selectedFlow.children.push(flowItem);
                        $scope.info.reqFlows.push(result.data);
                        $scope.info.reqNodeFlows = [];
                        $scope.info.reqRelateFlows = [];
                        angular.forEach($scope.info.reqFlows, function(flow) {
                            if(flow.status == "NODE_UPDATE") {
                                $scope.info.reqNodeFlows.push(flow);
                            } else {
                                $scope.info.reqRelateFlows.push(flow);
                            }
                        });
                    } else {
                        flowItem.level = parseInt(flowData.item.level) + 1;
                        flowItem.status = "ADD";
                        $scope.info.my_tree.set_select_branch_by_id(postParams.bussinessId);
                        $timeout(function() {
                            if(!$scope.info.selectedFlow.children.length) {
                                $scope.info.selectedFlow.children = [];
                            }
                            $scope.info.selectedFlow.children.push(flowItem);
                            $scope.info.reqFlows.push(flowItem);
                            $scope.info.reqNodeFlows = [];
                            $scope.info.reqRelateFlows = [];
                            angular.forEach($scope.info.reqFlows, function(flow) {
                                if(flow.status == "NODE_UPDATE") {
                                    $scope.info.reqNodeFlows.push(flow);
                                } else {
                                    $scope.info.reqRelateFlows.push(flow);
                                }
                            });
                        }, 1000);
                    }
                } else {
                    var metaData = {
                        id     : postParams.id,
                        name   : postParams.name,
                        reqId  : postParams.reqId,
                        attrs  : $scope.info.selectedFlow.metaData.attrs,
                        status : $scope.info.selectedFlow.metaData.status,
                        bussinessId  : $scope.info.selectedFlow.metaData.bussinessId,
                        attrConfigId : $scope.info.selectedFlow.metaData.attrConfigId
                    }
                    $scope.info.selectedFlow.name = postParams.name;
                    $scope.info.selectedFlow.metaData = metaData;
                    if($scope.info.hasRelate) {
                        getReqFlows(postParams.reqId);
                    }
                }
                $scope.info.currentDiagram = true;
                $rootScope.toasterSuccessInfo(flowData.type == "add" ? "创建成功！" : (flowData.type == "edit" ? "修改成功！" : "复制成功！"));
            } else {
                $rootScope.toasterErrorInfo(result.desc);
            }
        });
    };

    //删除流程
    $scope.removeFlow = function () {
        if (!$scope.info.selectedFlow) {
            $rootScope.toasterWarningInfo("请选择要输出的流程！");
            return false;
        }
        //frame为1，不可删除     flow为2，可以删除
        if ($scope.info.selectedFlow.type == "1") {
            $rootScope.toasterWarningInfo("结构类型流程不能删除！");
            return false;
        }
        var url = matrix_product_url + "/flow/deleteFlow?flowId=" + $scope.info.selectedFlow.id;
        $http.get(url).success(function (result) {
            if (result.code == "0") {
                var selectedParent = $scope.info.my_tree.get_parent_branch($scope.info.selectedFlow);
                var selectedParentArray = [];
                selectedParentArray = selectedParent ? selectedParent.children : $scope.info.flowTree;
                lodash.remove(selectedParentArray, {id: $scope.info.selectedFlow.id});
                $scope.info.removeFinished = true;
                $rootScope.toasterSuccessInfo("删除成功！");
            } else {
                $rootScope.toasterErrorInfo(result.desc);
            }
        });
    };

    //获取req关联的flow列表
    function getReqFlows(reqId) {
        var url = matrix_product_url +"/flow/getReqFlows?reqId="+ reqId;
        $http.get(url).success(function(result) {
            if(result.code == "0") {
                if(!result.data) {
                    $rootScope.toasterErrorInfo("获取req关联流程数据错误！");
                } else {
                    angular.forEach(result.data, function(flow) {
                        if(flow.status == "NODE_UPDATE") {
                            $scope.info.reqNodeFlows.push(flow);
                        } else {
                            $scope.info.reqRelateFlows.push(flow);
                        }
                    });
                    $scope.info.reqFlows = result.data;
                }
            } else {
                $rootScope.toasterErrorInfo(result.desc);
            }
        });
    };

    //定位
    $scope.goTo = function(relate) {
        if(relate.id) {
            $scope.info.jumpToFeature = relate.id;
            $scope.info.my_tree.set_select_branch_by_id(relate.id);
        }
    };

    //关联流程
    $scope.relateFlow = function() {
        var flowId = $scope.info.selectedFlow.id;
        if(!flowId) {
            $rootScope.toasterErrorInfo("关联流程id错误！");
            return false;
        }
        var url = matrix_product_url +"/flow/relateWithFlow?flowId="+ flowId +"&reqId="+ $scope.info.currentReqId;
        $http.get(url).success(function(result) {
            if(result.code == "0") {
                $scope.info.hasRelate = $scope.info.selectedFlow.metaData;
                if($scope.info.selectedFlow.metaData.status == "NODE_UPDATE") {
                    $scope.info.reqNodeFlows.push($scope.info.selectedFlow.metaData);
                } else {
                    $scope.info.reqRelateFlows.push($scope.info.selectedFlow.metaData);
                }
                $scope.info.reqFlows.push($scope.info.selectedFlow.metaData);
                $scope.info.isDisabled = false;
                $scope.info.currentDiagram = true;
                $scope.info.viewStatus = "current";
                $scope.info.diagramStatus = "current";
                $scope.info.jumpToFeature = $scope.info.selectedFlow.id;
                getFlowDetailsOfNode($scope.info.selectedFlow.id, $scope.info.currentReqId);
                $rootScope.toasterSuccessInfo("流程关联成功！");
            } else {
                $rootScope.toasterErrorInfo(result.desc);
            }
        });
    };

    //解除关联
    $scope.reliveFlow = function() {
        var flowId = $scope.info.selectedFlow.id;
        if(!flowId) {
            $rootScope.toasterErrorInfo("关联流程id错误！");
            return false;
        }
        var url = matrix_product_url +"/flow/dissociateWithFlow?flowId="+ flowId +"&reqId="+ $scope.info.currentReqId;
        $http.get(url).success(function(result) {
            if(result.code == "0") {
                $scope.info.hasRelate = undefined;
                lodash.remove($scope.info.reqFlows, {id: flowId});
                $scope.info.reqNodeFlows = [];
                $scope.info.reqRelateFlows = [];
                angular.forEach($scope.info.reqFlows, function(flow) {
                    if(flow.status == "NODE_UPDATE") {
                        $scope.info.reqNodeFlows.push(flow);
                    } else {
                        $scope.info.reqRelateFlows.push(flow);
                    }
                });
                $scope.info.viewStatus = "online";
                $scope.info.diagramStatus = "online";
                $scope.info.isDisabled = true;
                $scope.info.jumpToFeature = "";
                getFlowDetailsOfNode($scope.info.selectedFlow.id, "-1");
                $scope.info.selectedFlow.type = "-1";
                $rootScope.toasterSuccessInfo("重置成功！");
            } else {
                $rootScope.toasterErrorInfo(result.desc);
            }
        });

    };

    //节点内容--功能点点击
    $scope.nodeClick = function() {
        var url = matrix_product_url +"/feature/featureOccupy?reqId="+ $scope.info.currentReqId +"&id="+ $scope.info.model.selectedFlowData.feature_id;
        $http.get(url).success(function(result) {
            if(result.code == "0") {
                $scope.info.model.selectedFlowData.hasRelateFeature = true;
                var nodeDataArray = angular.copy($scope.info.model.nodeDataArray);
                var linkDataArray = angular.copy($scope.info.model.linkDataArray);
                angular.forEach(nodeDataArray, function(node) {
                    if(node.feature_id == $scope.info.model.selectedFlowData.feature_id) {
                        node.isHighlighted = "isRelate";
                    }
                });
                $scope.info.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
                $rootScope.toasterSuccessInfo("关联功能点成功！");
            } else {
                $rootScope.toasterErrorInfo(result.desc);
            }
        });
    };

    //标题失焦点保存
    $scope.updateNodeName = function () {
        var nodeDataArray = lodash.findWhere($scope.info.nodeDataArray, {feature_id: $scope.info.model.selectedFlowData.feature_id});
        nodeDataArray.text = $scope.info.model.selectedFlowData.text;
        $scope.info.model = new go.GraphLinksModel($scope.info.nodeDataArray, $scope.info.linkDataArray);
    };

    //切换节点状态保存
    $scope.selectStatusItem = function (item) {
        var nodeDataArray = lodash.findWhere($scope.info.nodeDataArray, {feature_id: $scope.info.model.selectedFlowData.feature_id});
        nodeDataArray.status = item.key;
        nodeDataArray.feature_info.status = item.key;
        nodeDataArray.isHighlighted = true;
        $scope.info.model = new go.GraphLinksModel($scope.info.nodeDataArray, $scope.info.linkDataArray);
    };

    /**
     * 查询节点信息
     * 1：数据格式要与查询的内容保持一致
     * 2：节点要添加fill(背景色)高粱属性：isHighlighted
     */
    $scope.searchNode = function () {
        console.log("查询输入框内容");
        console.log($scope.info.input);
        $scope.info.diagramScope.searchNode($scope.info.input);
    }

    // ************NEW**************
    
    //节点回车查询
    $scope.myKeyup = function(e) {
        var keyCode = window.event?e.keyCode:e.which;
        if(keyCode == 13) {
            $scope.searchNode();
        }
    };

    //切换流程模式（当前，线上，对比）
    $scope.clickStatus = function(status) {
        console.log(status);
        if(!$scope.info.selectedFlow.id) {
            return false;
        }
        //type    1: frame   2: flow
        if($scope.info.selectedFlow.type == "1") {
            return false;
        }
        var isRelateFlow = "";
        var isRelateFlow = lodash.findWhere($scope.info.reqFlows, {id: $scope.info.selectedFlow.id});
        if(isRelateFlow == undefined) {
            return false;
        }
        switch(status) {
            case "current":
                $scope.info.diagramStatus = "current";
                getFlowDetailsOfNode($scope.info.selectedFlow.id, $stateParams.reqId ? $stateParams.reqId : "-1");
                break;
            case "online":
                $scope.info.diagramStatus = "online";
                getFlowDetailsOfNode($scope.info.selectedFlow.id, "-1");
                break;
            case "compare":
                $scope.info.diagramStatus = "compare";
                getFlowDetailsOfNode($scope.info.selectedFlow.id, $stateParams.reqId ? $stateParams.reqId : "-1");
                getFlowDetailsOfNode($scope.info.selectedFlow.id, "-1");
                break;
        }
    };

    $scope.addFeatureOrFlow = function(data) {
        var modalInstance = $modal.open({
            animation: true,
            templateUrl: getTemplateUrl("matrix/component/tpl/flowNodeModal.html"),
            controller: "addFeatureOrFlowCtrl",
            keyboard: true,
            backdrop: true,
            resolve: {
                data: function () {
                    return data;
                }
            }
        });

        modalInstance.result.then(function (nodeItem) {
            setFeatureOrFlow(nodeItem);
        }, function (reason) {
            console.log("关闭modal");
        });
    };

    function setFeatureOrFlow(nodeItem) {
        var obj = $scope.info.diagramScope.obj;
        var category = $scope.info.diagramScope.category;
        $scope.info.diagramScope.propAddNodeAndLink(obj, category, nodeItem);
    }

    // 获取点击的节点详细信息
    $scope.getNodeDetails = function(data) {
        console.log(data);
    };

    function updateFlowDetails2() {
        $scope.info.diagramScope.save();
        console.log("外部调用获取里面的值");
        var nodeData = JSON.parse($scope.info.diagramScope.flowData);
        console.log(nodeData.nodeDataArray);
        console.log(nodeData.linkDataArray);
        var currentDate = Number(new Date());
        var postParams = {
            reqId: $stateParams.reqId ? $stateParams.reqId : "-1",
            flowId: $scope.info.flowId, 
            attrs: {
                "date": currentDate,
                "version": $scope.info.flowDetails.attrs.version,
                "req_snapshot": $scope.info.flowDetails.attrs.req_snapshot,
                "master_version": $scope.info.flowDetails.attrs.master_version,
                "nodeDataArray": nodeData.nodeDataArray || [],
                "linkDataArray": nodeData.linkDataArray || [],
            }
        };

        console.log(JSON.stringify(preventCircularJson(postParams)));
        var url = matrix_product_url + "/flow/updateReqFlowContent";
        $http({
            method: "post",
            url: url,
            data: JSON.stringify(postParams),
            headers: {"Content-Type": "application/json"}
        }).success(function (result) {
            if (result.code == "0") {
                $rootScope.toasterSuccessInfo("保存成功！");
            } else {
                $rootScope.toasterErrorInfo("保存失败，请刷新重试！");
            }
        });
    };
}]);

app.controller("addFeatureOrFlowCtrl", ["$scope", "$rootScope", "$modalInstance", "$http", "data", function($scope, $rootScope, $modalInstance, $http, data) {
    var flagName = "";
    switch(data.flag) {
        case "JUMP": 
            flagName = "【页面跳转】";
            break;
        case "UI": 
            flagName = "【页面交互】";
            break;
        case "FORM": 
            flagName = "【信息提交】";
            break;
        case "SCAN": 
            flagName = "【扫描】";
            break;
    }
    $scope.flowTypeName = "引入" + (data.type == "Feature" ? ("功能点" + (flagName)) : "流程");
    $scope.promptName = data.type == "Feature" ? "请选择功能点" : "请选择流程";
    $scope.isAddFeatureOrFlow = true;
    $scope.sysArray = config_flow_legend_sys;
    $scope.ffDataArray = [];

    data.type == "Feature" ? getAllFeature() : getFlowTree();

    $scope.switchSys = function(item) {
        getAllFeature(item.crtname);
    }

    // 获取功能点数据
    function getAllFeature() {
        $("#showLoading").css("display", "block");
        $("#showList").css("display", "none");
        $scope.ffDataArray = new Array();
        var url = matrix_product_url +"/feature/getFeature?withPrototype=1&withAttr=0";
        $http.get(url).success(function(result) {
            if(result.code == "0") {
                angular.forEach(result.data, function(data) {
                    data.crtname = (data.path || "") + "/" + (data.featureName || "");
                });
                angular.forEach(result.data, function(resData) {
                    if(sys) {
                        if(resData.sys == sys) {
                            $scope.ffDataArray.push(resData);
                        }
                    } else {
                        $scope.ffDataArray.push(resData);
                    }
                });
            } else {
                $rootScope.toasterErrorInfo("获取功能点数据错误！");
            }
            $("#showLoading").css("display", "none");
            $("#showList").css("display", "block");
        });
    }

    // 获取流程树
    function getFlowTree() {
        $("#showLoading").css("display", "block");
        $("#showList").css("display", "none");
        var url = matrix_product_url + "/flow/getFlowTree";
        $http.get(url).success(function (result) {
            if (result.code == "0") {
                $scope.ffDataArray = setFlowLegendPath(result.data.children, [], "");
            } else {
                $rootScope.toasterErrorInfo(result.desc);
            }
            $("#showLoading").css("display", "none");
            $("#showList").css("display", "block");
        });
    };

    // 解析流程树数据
    function setFlowLegendPath(featureTree, resultFeatureArray, featureName) {
        angular.forEach(featureTree, function (feature, index) {
            var pathUrl = featureName ? featureName + "/" + feature.name : feature.name;
            //type  1: frame   2: flow
            if(feature.type == "2") {
                var featureItem = {
                    crtname: pathUrl,
                    flowname: feature.name,
                    status: feature.status,
                    path: featureName
                }
                resultFeatureArray.push(featureItem);
            }
            if (feature.children && feature.children.length) {
                setFlowLegendPath(feature.children, resultFeatureArray, feature.name);
            }
        });
        return resultFeatureArray;
    };

    $scope.createClick = function () {
        if (!$scope.sltLegendItem) {
            $rootScope.toasterWarningInfo("引入节点数据不能为空！");
            return false;
        }
        $modalInstance.close($scope.sltLegendItem);
    };

    $scope.cancelClick = function () {
        $modalInstance.dismiss("cancel");
    };
}]);

app.controller("editFlowCtrl", ["$scope", "$rootScope", "$modalInstance", "$http", "type", "defaultValue", "flowDetails", function ($scope, $rootScope, $modalInstance, $http, type, defaultValue, flowDetails) {
    $scope.flowId = "";
    $scope.flowType = type;
    $scope.flowTypeName = type == "add" ? "新建流程" : (type == "edit" ? "编辑流程" : "复制流程");
    $scope.treeData = [];
    $scope.flowItem = {};
    $scope.dataCrtValue = "请选择节点";
    if(type == "edit") {
        if(defaultValue) {
            $scope.flowName = defaultValue.name;
        } else {
            $scope.flowName = "";
        }
    } else {
        $scope.flowName = "";
    }
    if(type == "copy") {
        getFlowFrameTree();
    }

    //获取流程架构树数据
    function getFlowFrameTree() {
        var url = matrix_product_url + "/flowFrame/getFlowFrameTree";
        $http.get(url).success(function (result) {
            if (result.code == "0") {
                $scope.treeData = result.data.children;
            } else {
                $rootScope.toasterErrorInfo(result.desc);
            }
        });
    };

    $scope.selectProductLine = function (item, selectedItems) {
        $scope.flowId = item.id;
        $scope.flowItem = item;
        $scope.dataCrtValue = item.name;
    };

    $scope.createClick = function () {
        if ($scope.flowName == defaultValue.name) {
            $rootScope.toasterWarningInfo("流程名称不能重复！");
            return false;
        }
        if(type == "copy") {
            if (!$scope.flowId) {
                $rootScope.toasterWarningInfo("复制节点不能为空！");
                return false;
            }
        }
        var flowData = {
            id: $scope.flowId,
            name: $scope.flowName,
            type: type,
            attrs: flowDetails.attrs,
            item: $scope.flowItem
        };
        $modalInstance.close(flowData);
    };

    $scope.cancelClick = function () {
        $modalInstance.dismiss("cancel");
    };
}]);

app.directive('goDiagram', function ($http, $rootScope, lodash) {
    return {
        restrict: 'E',
        template: '<div class="col-sm-12"  id="diagramContent" style="background-color: white;">' +
                  '    <div id="myPaletteDiv" ng-hide="showLegend" style="border-bottom: 1px solid #cfdadd; height: 75px; width: 100%; white-space: nowrap; overflow-x: hidden; overflow-y: hidden;"></div>'+
                  '    <div id="myDiagramDiv" class="col-sm-12" style="height: 600px;"></div>' +
                  '</div>',
        replace: true,
        scope: {
            reqId      : '=',
            model      : '=goModel',
            paModel    : '=paModel',
            diagramD   : '=diagram',
            mDiagram   : '=',
            flowVersion: '=',
            showLegend : '='
            // clickFun: '&'
        },
        link: function (scope, element, attrs) {

            scope.requestFullScreen = function() {
                var elem = document.getElementById("diagramContent");  
                var heightDiagram = document.body.clientWidth;
                document.getElementById("myDiagramDiv").style.height = heightDiagram +"px";
                document.getElementById("fullscreen").style.display = 'none';
                document.getElementById("resize").style.display = 'inline-block';
                requestFullScreen(elem);
            };

            function requestFullScreen(element) {    
                var requestMethod = element.requestFullScreen || element.webkitRequestFullScreen || element.mozRequestFullScreen || element.msRequestFullScreen;    
                if (requestMethod) {      
                    requestMethod.call(element);
                } else if (typeof window.ActiveXObject !== "undefined") {      
                    var wscript = new ActiveXObject("WScript.Shell");    
                    if (wscript !== null) {    
                        wscript.SendKeys("{F11}");    
                    }    
                }
            }

            scope.exitFullscreen = function() {
                var de = document;
                if (de.exitFullscreen) {
                    de.exitFullscreen();
                } else if (de.mozCancelFullScreen) {
                    de.mozCancelFullScreen();
                } else if (de.webkitCancelFullScreen) {
                    de.webkitCancelFullScreen();
                }
                document.getElementById("myDiagramDiv").style.height = "600px";
                document.getElementById("fullscreen").style.display = 'inline-block';
                document.getElementById("resize").style.display = 'none';
            };
            document.addEventListener("mozfullscreenchange", function(e) {
                setStyle(e.currentTarget.mozFullScreen);
            });
            document.addEventListener("webkitfullscreenchange", function(e) {
                setStyle(e.currentTarget.webkitIsFullScreen);
            });
            document.addEventListener("msfullscreenchange", function(e) {
                console.log("msfullscreenchange", e);
            });

            function setStyle(type) {
                if(type == false) {
                    scope.exitFullscreen();
                }
            };
            
            var $ = go.GraphObject.make;
            var diagram =
                $(go.Diagram, "myDiagramDiv",
                    {   
                        grid: $(go.Panel, "Grid", { gridCellSize: new go.Size(8, 8) },
                            $(go.Shape, "LineH", { stroke: "lightgray", strokeWidth: 0.5 }),
                            $(go.Shape, "LineV", { stroke: "lightgray", strokeWidth: 0.5 })
                        ),
                        "toolManager.mouseWheelBehavior": go.ToolManager.WheelZoom,   //鼠标滚轮放大缩小
                        nodeTemplate: $(go.Node, "Auto", {
                                selectable: false
                            }
                        ),
                        linkTemplate: $(go.Link,
                            {
                                routing: go.Link.AvoidsNodes,
                                curve: go.Link.JumpOver,
                                corner: 5, toShortLength: 4,
                                relinkableFrom: true,
                                relinkableTo: true,
                                reshapable: true,
                                resegmentable: true,
                                selectable: true,
                                mouseEnter: function (e, link) {
                                    link.findObject("HIGHLIGHT").stroke = "rgba(30,144,255,0.2)";
                                },
                                mouseLeave: function (e, link) {
                                    link.findObject("HIGHLIGHT").stroke = "transparent";
                                }
                            },
                            $(go.Shape,
                                {isPanelMain: true, strokeWidth: 8, stroke: "transparent", name: "HIGHLIGHT"}),
                            $(go.Shape,
                                {isPanelMain: true, stroke: "gray", strokeWidth: 2}),
                            $(go.Shape,
                                {toArrow: "standard", stroke: null, fill: "gray"}),
                            $(go.Panel, "Auto",
                                {visible: false, name: "LABEL", segmentIndex: 2, segmentFraction: 0.5},
                                new go.Binding("visible", "visible").makeTwoWay(),
                                $(go.Shape, "RoundedRectangle",
                                    {fill: "#F8F8F8", stroke: null}),
                                $(go.TextBlock, "Yes",
                                    {
                                        textAlign: "center",
                                        font: "10pt helvetica, arial, sans-serif",
                                        stroke: "#333333",
                                        editable: true
                                    },
                                    new go.Binding("text").makeTwoWay())
                            )
                        ),
                        initialContentAlignment: go.Spot.MiddleTop,
                        "ModelChanged": updateAngular,
                        "ChangedSelection": updateSelection,
                        allowDrop: true,
                        "LinkDrawn": showLinkLabel,
                        "LinkRelinked": showLinkLabel,
                        scrollsPageOnFocus: false,
                        allowCopy: true,//不允许在流程里面复制节点
                        // isReadOnly: true,
                        "undoManager.isEnabled": true
                    });
            var lightText = 'whitesmoke';
            scope.mDiagram = diagram;

            //自适应高度
            scope.setTableHeight = function() {
                    var h = document.documentElement.clientHeight || document.body.clientHeight;
                    h = h - 300;
                    document.getElementById("myDiagramDiv").style.height = h + "px";
            }
            scope.setTableHeight();
            window.onresize = scope.setTableHeight;

            //GoJs点击事件
            diagram.addDiagramListener("ObjectSingleClicked", function (e) {
                //scope.clickFun({data: e.subject.part.data});
            });

            //设置节点样式
            function nodeStyle() {
                return [
                    new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
                    {
                        locationSpot: go.Spot.Center,
                        mouseEnter: function (e, obj) {
                            showPorts(obj.part, true);
                        },
                        mouseLeave: function (e, obj) {
                            showPorts(obj.part, false);
                        }
                    }
                ];
            }

            //设置节点上下左右的连接点
            function makePort(name, spot, output, input) {
                return $(go.Shape, "Circle",
                    {
                        fill: "transparent",
                        stroke: null,
                        desiredSize: new go.Size(8, 8),
                        alignment: spot, alignmentFocus: spot,
                        portId: name,
                        fromSpot: spot, toSpot: spot,
                        fromLinkable: output, toLinkable: input,
                        cursor: "pointer"
                    });
            }

            //颜色
            var bluegrad = $(go.Brush, "Linear", {0: "#C4ECFF", 1: "#70D4FF"});

            //模板局部样式
            var actionTemplate = $(go.Panel, "Horizontal",
                $(go.Shape,
                    {width: 12, height: 12},
                    new go.Binding("figure"),
                    new go.Binding("fill")
                ),
                $(go.TextBlock,
                    {font: "10pt Verdana, sans-serif", editable: true},
                    new go.Binding("text").makeTwoWay()
                )
            );

            /**
             * 为节点模板添加自定义的节点样式
             * 类型：长方形可输入文本框
             */
            diagram.nodeTemplateMap.add("",
                $(go.Node, "Spot", nodeStyle(),
                    $(go.Panel, "Auto",
                        $(go.Shape, "RoundedRectangle",
                            {fill: "#edf1f2", stroke: null, minSize: new go.Size(35, 35)},
                            new go.Binding("figure", "figure")
                        ),
                        $(go.TextBlock,
                            {
                                font: "bold 11pt Helvetica, Arial, sans-serif",
                                stroke: '#454545',
                                margin: 8,
                                maxSize: new go.Size(160, NaN),
                                wrap: go.TextBlock.WrapFit,
                                editable: true
                            },
                            new go.Binding("text").makeTwoWay()
                        )
                    ),
                    //设置节点的连接点
                    makePort("T", go.Spot.Top, false, true),
                    makePort("L", go.Spot.Left, true, true),
                    makePort("R", go.Spot.Right, true, true),
                    makePort("B", go.Spot.Bottom, true, false)
                )
            );

            /**
             * 开始节点
             */
            diagram.nodeTemplateMap.add("Start",
                $(go.Node, "Spot", nodeStyle(),
                    $(go.Panel, "Auto",
                        $(go.Shape, "Circle",
                            {minSize: new go.Size(40, 40), fill: "#edf1f2", stroke: null}
                        ),
                        $(go.TextBlock, "Start",
                            {font: "bold 11pt Helvetica, Arial, sans-serif", stroke: '#454545'},
                            new go.Binding("text")
                        )
                    ),
                    makePort("L", go.Spot.Left, true, false),
                    makePort("R", go.Spot.Right, true, false),
                    makePort("B", go.Spot.Bottom, true, false)
                )
            );

            /**
             * 结束节点
             */
            diagram.nodeTemplateMap.add("End",
                $(go.Node, "Spot", nodeStyle(),
                    $(go.Panel, "Auto",
                        $(go.Shape, "Circle",
                            {minSize: new go.Size(40, 40), fill: "#edf1f2", stroke: null}
                        ),
                        $(go.TextBlock, "Start",
                            {font: "bold 11pt Helvetica, Arial, sans-serif", stroke: '#454545'},
                            new go.Binding("text")
                        )
                    ),
                    makePort("T", go.Spot.Top, false, true),
                    makePort("L", go.Spot.Left, false, true),
                    makePort("R", go.Spot.Right, false, true)
                )
            );

            /**
             * comment节点
             */
            diagram.nodeTemplateMap.add("Comment",
                $(go.Node, "Auto", nodeStyle(),
                    $(go.Shape, "Card",
                        {minSize: new go.Size(100, 40),fill: "#EFFAB4", stroke: null}
                    ),
                    $(go.TextBlock,
                        {
                            margin: 5,
                            maxSize: new go.Size(200, NaN),
                            wrap: go.TextBlock.WrapFit,
                            textAlign: "left",
                            editable: true,
                            font: "bold 8pt Helvetica, Arial, sans-serif",
                            stroke: '#2477c9'
                        },
                        new go.Binding("text").makeTwoWay()
                    )
                )
            );

            /**
             * 自定义节点图例
             */
            diagram.nodeTemplateMap.add("formula",
                $(go.Node, "Auto", nodeStyle(),
                    {
                        mouseDragEnter: function (e, grp, prev) {
                            highlightGroup(e, grp, true);
                        },
                        mouseDragLeave: function (e, grp, next) {
                            highlightGroup(e, grp, false);
                        },
                        //mouseDrop: finishDrop,
                    },
                    $(go.Shape, "RoundedRectangle",
                        {
                            fill: "white", stroke: "white", margin: new go.Margin(5, 5, 5, 5),
                        }
                    ),
                    new go.Binding("background", "isHighlighted", function (h) {
                        return h ? "#DC3C00" : "#edf1f2";
                    }).ofObject(),
                    $(go.Panel, "Vertical",
                        {stretch: go.GraphObject.Horizontal, background: "#edf1f2", margin: new go.Margin(5, 5, 5, 5)},
                        new go.Binding("background", "isHighlighted", function (h) {
                            var crtColor = "";
                            var updateColor = "#f7df66", defaultColor = "#edf1f2", flowColor = "#CD96CD", nodeUpdateColor = "#EE6363";
                            switch(h) {
                                case "flow":
                                    crtColor = nodeUpdateColor;
                                    break;
                                case "ADD":
                                    crtColor = nodeUpdateColor;
                                    break;
                                case "isRelate":
                                    crtColor = updateColor;
                                    break;
                                default: 
                                    crtColor = defaultColor;
                            }
                            return crtColor;
                        }).makeTwoWay(),
                        $(go.Panel, "Table",
                            {stretch: go.GraphObject.Horizontal},
                            $(go.TextBlock,
                                {
                                    alignment: go.Spot.Left,
                                    margin: new go.Margin(5, 0, 5, 5),
                                    stroke: "#58666e",
                                    font: "10pt Verdana, sans-serif"
                                },
                                new go.Binding("text", "text").makeTwoWay()
                            )
                        ),
                        $(go.Panel, "Table",
                            {stretch: go.GraphObject.Horizontal},
                            $(go.TextBlock,
                                {
                                    alignment: go.Spot.Left,
                                    margin: new go.Margin(5, 0, 5, 5),
                                    stroke: "#58666e",
                                    font: "8pt Verdana, sans-serif"
                                },
                                new go.Binding("text", "sys").makeTwoWay()
                            ),
                            $("PanelExpanderButton", "COLLAPSIBLE",
                                {column: 1, alignment: go.Spot.Left, margin: new go.Margin(0, 10, 0, 0),}
                            )
                        ),
                        $(go.Panel, "Table",
                            {
                                name: "COLLAPSIBLE",
                                visible: false,     
                                stretch: go.GraphObject.Horizontal,
                                itemTemplate: actionTemplate
                            },
                            $(go.TextBlock, textStyle(),
                                {row: 1, column: 0},
                                new go.Binding("text", "nodeType", function(nodeType) {
                                    return nodeType == "flow" ? "名称：" : "功能点名称：";
                                }).makeTwoWay()
                            ),
                            $(go.TextBlock, textStyle(),
                                {
                                    row: 1, column: 1, columnSpan: 4,
                                    editable: false, isMultiline: false,
                                    minSize: new go.Size(10, 14),
                                    margin: new go.Margin(0, 0, 5, 3)
                                },
                                new go.Binding("text", "relate_name").makeTwoWay()
                            ),
                            $(go.TextBlock, textStyle(),
                                {row: 2, column: 0},
                                new go.Binding("text", "nodeType", function(nodeType) {
                                    return nodeType == "flow" ? "场景：" : "菜单路径：";
                                }).makeTwoWay()
                            ),
                            $(go.TextBlock, textStyle(),
                                {
                                    row: 2, column: 1, columnSpan: 4,
                                    editable: false, isMultiline: false,
                                    minSize: new go.Size(10, 14),
                                    margin: new go.Margin(0, 0, 5, 3)
                                },
                                new go.Binding("text", "relate_path").makeTwoWay()
                            )
                        )
                    ),
                    makePort("T", go.Spot.Top, true, true),
                    makePort("L", go.Spot.Left, true, true),
                    makePort("R", go.Spot.Right, true, true),
                    makePort("B", go.Spot.Bottom, true, true)
                )
            );

            /**
             * 线
             */
            diagram.nodeTemplateMap.add("Line", 
                $(go.Node, "Spot", nodeStyle(),
                    {
                        locationSpot: go.Spot.Center,
                        locationObjectName: "SHAPE",
                        selectionAdorned: false,
                        resizable: true,
                        resizeObjectName: "SHAPE",
                        rotatable: true,
                        rotateObjectName: "SHAPE",
                        layoutConditions: go.Part.LayoutStandard & ~go.Part.LayoutNodeSized
                    },
                    new go.Binding("width", "length").makeTwoWay(),
                    $(go.Shape, {
                        figure: "LineH",
                        strokeWidth: 5,
                        stroke: "lightcoral",
                        interval: 10
                    }
                    )
                )
            );

            go.Shape.defineFigureGenerator("LineH", function (shape, w, h) {
                var geo = new go.Geometry(go.Geometry.Line);
                geo.startX = 0;
                geo.startY = h / 2;
                geo.endX = w;
                geo.endY = h / 2;
                return geo;
            });

            /**
             * 竖线
             */
            diagram.nodeTemplateMap.add("vLine", 
                $(go.Node, "Spot", nodeStyle(),
                    {
                        locationSpot: go.Spot.Center,
                        locationObjectName: "SHAPE",
                        selectionAdorned: false,
                        resizable: true,
                        resizeObjectName: "SHAPE",
                        rotatable: true,
                        rotateObjectName: "SHAPE",
                        layoutConditions: go.Part.LayoutStandard & ~go.Part.LayoutNodeSized
                    },
                    new go.Binding("height", "length").makeTwoWay(),
                    $(go.Shape, { 
                        figure: "LineV",
                        strokeWidth: 5,
                        stroke: "lightcoral",
                        interval: 10
                    })
                )
            );

            go.Shape.defineFigureGenerator("LineV", function (shape, w, h) {
                var geo = new go.Geometry(go.Geometry.Line);
                geo.startX = w / 2;
                geo.startY = 10;
                geo.endX = w / 2;
                geo.endY = h;
                return geo;
            });

            /**
             * user
             */
            diagram.nodeTemplateMap.add("User", 
                $(go.Node, "Spot", nodeStyle(),
                    {
                        locationSpot: go.Spot.Center,
                        locationObjectName: "BpmnTaskUser",
                        selectionAdorned: false,
                        //resizable: true,   //是否允许缩放
                        resizeObjectName: "BpmnTaskUser",
                        //rotatable: true,   //是否允许旋转
                        rotateObjectName: "BpmnTaskUser",
                        layoutConditions: go.Part.LayoutStandard & ~go.Part.LayoutNodeSized
                    },
                    $(go.Panel, "Vertical",  
                        $(go.Shape, "BpmnTaskUser",
                            { alignmentFocus: go.Spot.TopLeft,
                            fill: "#edf1f2",
                            width: 30, height: 30,
                            },
                            new go.Binding("figure", "taskType", nodeActivityTaskTypeConverter)
                        ),
                        $(go.TextBlock,
                            {
                                font: "bold 11pt Helvetica, Arial, sans-serif",
                                margin: new go.Margin(8, 8, 8, 8),
                                maxSize: new go.Size(160, NaN),
                                wrap: go.TextBlock.WrapFit,
                                editable: true
                            },
                            new go.Binding("text").makeTwoWay()
                        )
                    )
                )
            );

            go.Shape.defineFigureGenerator("BpmnTaskUser", function (shape, w, h) {
                var geo = new go.Geometry();
                var fig = new go.PathFigure(0, 0, false);
                geo.add(fig);
                var fig2 = new go.PathFigure(.335 * w, (1 - .555) * h, true);
                geo.add(fig2);
                // Shirt
                fig2.add(new go.PathSegment(go.PathSegment.Line, .335 * w, (1 - .405) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, (1 - .335) * w, (1 - .405) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, (1 - .335) * w, (1 - .555) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Bezier, w, .68 * h, (1 - .12) * w, .46 * h, (1 - .02) * w, .54 * h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, w, h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, 0, h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, 0, .68 * h));
                fig2.add(new go.PathSegment(go.PathSegment.Bezier, .335 * w, (1 - .555) * h, .02 * w, .54 * h, .12 * w, .46 * h));
                // Start of neck
                fig2.add(new go.PathSegment(go.PathSegment.Line, .365 * w, (1 - .595) * h));
                var radiushead = .5 - .285;
                var centerx = .5;
                var centery = radiushead;
                var alpha2 = Math.PI / 4;
                var KAPPA = ((4 * (1 - Math.cos(alpha2))) / (3 * Math.sin(alpha2)));
                var cpOffset = KAPPA * .5;
                var radiusw = radiushead;
                var radiush = radiushead;
                var offsetw = KAPPA * radiusw;
                var offseth = KAPPA * radiush;
                // Circle (head)
                fig2.add(new go.PathSegment(go.PathSegment.Bezier, (centerx - radiusw) * w, centery * h, (centerx - ((offsetw + radiusw) / 2)) * w, (centery + ((radiush + offseth) / 2)) * h, (centerx - radiusw) * w, (centery + offseth) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Bezier, centerx * w, (centery - radiush) * h, (centerx - radiusw) * w, (centery - offseth) * h, (centerx - offsetw) * w, (centery - radiush) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Bezier, (centerx + radiusw) * w, centery * h, (centerx + offsetw) * w, (centery - radiush) * h, (centerx + radiusw) * w, (centery - offseth) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Bezier, (1 - .365) * w, (1 - .595) * h, (centerx + radiusw) * w, (centery + offseth) * h, (centerx + ((offsetw + radiusw) / 2)) * w, (centery + ((radiush + offseth) / 2)) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, (1 - .365) * w, (1 - .595) * h));
                // Neckline
                fig2.add(new go.PathSegment(go.PathSegment.Line, (1 - .335) * w, (1 - .555) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, (1 - .335) * w, (1 - .405) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, .335 * w, (1 - .405) * h));
                var fig3 = new go.PathFigure(.2 * w, h, false);
                geo.add(fig3);
                // Arm lines
                fig3.add(new go.PathSegment(go.PathSegment.Line, .2 * w, .8 * h));
                var fig4 = new go.PathFigure(.8 * w, h, false);
                geo.add(fig4);
                fig4.add(new go.PathSegment(go.PathSegment.Line, .8 * w, .8 * h));
                return geo;
            });

            function nodeActivityTaskTypeConverter(s) {
                var tasks = ["BpmnTaskUser"];
                if (s < tasks.length) return tasks[s];
                return "NotAllowed"; // error
            }

            function finishDrop(e, grp) {
                var ok = (grp !== null
                    ? grp.addMembers(grp.diagram.selection, true)
                    : e.diagram.commandHandler.addTopLevelParts(e.diagram.selection, true));
            }

            function highlightGroup(e, grp, show) {
                if (!grp) return;
                e.handled = true;
                if (show) {
                    // var tool = grp.diagram.toolManager.draggingTool;
                    // var map = tool.draggedParts || tool.copiedParts;
                    // if (grp.canAddMembers(map.toKeySet())) {
                    //     grp.isHighlighted = true;
                    //     return;
                    // }
                }
                grp.isHighlighted = false;
            }

            function textStyle() {
                return {font: "9pt sans-serif", stroke: "#58666e"};
            }

            function showPorts(node, show) {
                var diagram = node.diagram;
                if (!diagram || diagram.isReadOnly || !diagram.allowLink) return;
                node.ports.each(function (port) {
                    port.stroke = (show ? "black" : null);
                });
            }

            diagram.linkTemplate = $(go.Link,
                {
                    routing: go.Link.AvoidsNodes,
                    curve: go.Link.JumpOver,
                    corner: 5, toShortLength: 4,
                    relinkableFrom: true,
                    relinkableTo: true,
                    reshapable: true,
                    resegmentable: true,
                    mouseEnter: function (e, link) {
                        link.findObject("HIGHLIGHT").stroke = "rgba(30,144,255,0.2)";
                    },
                    mouseLeave: function (e, link) {
                        link.findObject("HIGHLIGHT").stroke = "transparent";
                    }
                },
                new go.Binding("points").makeTwoWay(),
                $(go.Shape,
                    {isPanelMain: true, strokeWidth: 8, stroke: "transparent", name: "HIGHLIGHT"}
                ),
                $(go.Shape,
                    {isPanelMain: true, stroke: "gray", strokeWidth: 2}
                ),
                $(go.Shape,
                    {toArrow: "standard", stroke: null, fill: "gray"}
                ),
                $(go.Panel, "Auto",
                    {visible: false, name: "LABEL", segmentIndex: 2, segmentFraction: 0.5},
                    $(go.Shape, "RoundedRectangle",
                        {fill: "#F8F8F8", stroke: null}
                    ),
                    $(go.TextBlock, "Yes",
                        {
                            textAlign: "center",
                            font: "10pt helvetica, arial, sans-serif",
                            stroke: "#333333",
                            editable: true
                        },
                        new go.Binding("text").makeTwoWay()
                    ),
                    new go.Binding("visible", "visible").makeTwoWay()
                )
            );

            function updateAngular(e) {
                // if (e.isTransactionFinished) {
                //     scope.$apply();
                // }
            }

            function updateSelection(e) {
                diagram.model.selectedFlowData = null;
                var it = diagram.selection.iterator;
                while (it.next()) {
                    var selnode = it.value;
                    // ignore a selected link or a deleted node
                    if (selnode instanceof go.Node && selnode.data !== null) {
                        if (selnode.data.feature_info) {
                            angular.forEach(config_flow_legend_type, function (type) {
                                if (selnode.data.feature_info.type == type.key) {
                                    selnode.data.feature_info.typeName = type.value;
                                }
                            });
                            selnode.data.sltStatusItem = "";
                            angular.forEach(config_flow_node_status, function (status) {
                                if (selnode.data.status == status.key) {
                                    selnode.data.sltStatusItem = status;
                                }
                            });
                        }
                        if(selnode.data.isFeature) {
                            relateFeature(selnode.data);
                        } else {
                            diagram.model.selectedFlowData = selnode.data;
                        }
                        break;
                    }
                }
                scope.$apply();
            }

            function showLinkLabel(e) {
                var label = e.subject.findObject("LABEL");
                //新建或者修改连线时  把连线的状态设置为add
                e.subject.data.nodeStatus = "add";
                if (label !== null) label.visible = (e.subject.fromNode.data.figure === "Diamond");
                if (e.subject.fromNode.key == '1') {
                    $rootScope.toasterWarningInfo("不能重复链接");
                    diagram.commandHandler.deleteSelection();
                }
            }

            scope.$watch("model", function (newmodel) {
                var oldmodel = diagram.model;
                if (oldmodel !== newmodel) {
                    diagram.removeDiagramListener("ChangedSelection", updateSelection);
                    diagram.model = newmodel;
                    diagram.addDiagramListener("ChangedSelection", updateSelection);
                }
            });

            scope.$watch("model.selectedFlowData.name", function (newname) {
                if (!diagram.model.selectedFlowData) return;
                // disable recursive updates
                diagram.removeModelChangedListener(updateAngular);
                // change the name
                diagram.startTransaction("change name");
                // the data property has already been modified, so setDataProperty would have no effect
                var node = diagram.findNodeForData(diagram.model.selectedFlowData);
                if (node !== null) node.updateTargetBindings("name");
                diagram.commitTransaction("change name");
                // re-enable normal updates
                diagram.addModelChangedListener(updateAngular);
            });

            var palette = $(go.Palette, "myPaletteDiv",
                {
                    scrollsPageOnFocus: false,
                    nodeTemplateMap: diagram.nodeTemplateMap,
                    layout: $(go.GridLayout,
                        {sorting: go.GridLayout.Forward})
                }
            );

            scope.$watch("paModel", function (newmodel) {
                var oldmodel = palette.model;
                if (oldmodel !== newmodel) {
                    palette.model = newmodel;
                }
            });

            scope.diagramD = diagram;
            //监听新拖拽到画布的节点
            diagram.addModelChangedListener(function (evt) {
                // ignore unimportant Transaction events
                if (!evt.isTransactionFinished) return;
                var txn = evt.object;  // a Transaction
                if (txn === null) return;
                // iterate over all of the actual ChangedEvents of the Transaction
                txn.changes.each(function (e) {
                    // ignore any kind of change other than adding/removing a node
                    if (e.modelChange !== "nodeDataArray") return;
                    // record node insertions and removals
                    if (e.change === go.ChangedEvent.Insert) {
                        console.log(evt.propertyName + " added node with key: ");
                        console.log(e.newValue);
                        if (e.newValue.index > 4) {
                            e.newValue.nodeStatus = "add";
                            // } else if (e.change === go.ChangedEvent.Remove) {
                            //     console.log(evt.propertyName + " removed node with key: " + e.oldValue.key);
                        }
                    }
                });
            });

            //监听新拖拽的连线
            diagram.addModelChangedListener(function (evt) {
                // ignore unimportant Transaction events
                if (!evt.isTransactionFinished) return;
                var txn = evt.object;  // a Transaction
                if (txn === null) return;
                // iterate over all of the actual ChangedEvents of the Transaction
                txn.changes.each(function (e) {
                    // record node insertions and removals
                    if (e.change === go.ChangedEvent.Property) {
                        if (e.modelChange === "linkFromKey") {
                            console.log(evt.propertyName + " changed From key of link: " +
                                e.object + " from: " + e.oldValue + " to: " + e.newValue);
                        } else if (e.modelChange === "linkToKey") {
                            console.log(evt.propertyName + " changed To key of link: " +
                                e.object + " from: " + e.oldValue + " to: " + e.newValue);
                        }
                    } else if (e.change === go.ChangedEvent.Insert && e.modelChange === "linkDataArray") {
                        console.log(evt);
                        console.log(evt.propertyName + " added link: " + e.newValue);
                    } else if (e.change === go.ChangedEvent.Remove && e.modelChange === "linkDataArray") {
                        console.log(evt.propertyName + " removed link: " + e.oldValue);
                    }
                });
            });

            //判断当前req关联的feature集合
            function relateFeature(selnodeData) {
                var url = matrix_product_url +"/feature/getAllFeatureForReq?reqId="+ scope.reqId;
                $http.get(url).success(function(result) {
                    if(result.code == "0") {
                        var hasRelate = lodash.findWhere(result.data, {id: selnodeData.feature_id});
                        selnodeData.hasRelateFeature = hasRelate != undefined ? true : false;
                        diagram.model.selectedFlowData = selnodeData;
                    } else {
                        $rootScope.toasterErrorInfo(result.desc);
                    }
                });
            };
        }
    };
});

app.directive('compareDiagram', function ($http, $rootScope, lodash) {
    return {
        restrict: 'E',
        template: '<div class="col-sm-12">' +
                  '    <div id="myPaletteCompare" style="display: none; border-bottom: 1px solid #cfdadd; height: 75px; width: 100%; white-space: nowrap; overflow-x: hidden; overflow-y: hidden;"></div>'+
                  '    <div style="color: red; font-weight: bold; font-size: 20px;">{{flowVersion.name}} 【线上】</div>' +
                  '    <div id="myDiagramCompare" class="col-sm-12" style="height: 600px;"></div>' +
                  '</div>',
        replace: true,
        scope: {
            model: '=goModel',
            paModel: '=paModel',
            diagramD: '=diagram',
            reqId: '=',
            flowVersion: '=',
            mDiagram: '='
            // clickFun: '&'
        },
        link: function (scope, element, attrs) {
            var $ = go.GraphObject.make;
            var diagram =
                $(go.Diagram, "myDiagramCompare",
                    {
                        "toolManager.mouseWheelBehavior": go.ToolManager.WheelZoom,   //鼠标滚轮放大缩小
                        nodeTemplate: $(go.Node, "Auto", {
                                selectable: false
                            }
                        ),
                        linkTemplate: $(go.Link,
                            {
                                routing: go.Link.AvoidsNodes,
                                curve: go.Link.JumpOver,
                                corner: 5, toShortLength: 4,
                                relinkableFrom: true,
                                relinkableTo: true,
                                reshapable: true,
                                resegmentable: true,
                                selectable: true,
                                mouseEnter: function (e, link) {
                                    link.findObject("HIGHLIGHT").stroke = "rgba(30,144,255,0.2)";
                                },
                                mouseLeave: function (e, link) {
                                    link.findObject("HIGHLIGHT").stroke = "transparent";
                                }
                            },
                            $(go.Shape,
                                {isPanelMain: true, strokeWidth: 8, stroke: "transparent", name: "HIGHLIGHT"}),
                            $(go.Shape,
                                {isPanelMain: true, stroke: "gray", strokeWidth: 2}),
                            $(go.Shape,
                                {toArrow: "standard", stroke: null, fill: "gray"}),
                            $(go.Panel, "Auto",
                                {visible: false, name: "LABEL", segmentIndex: 2, segmentFraction: 0.5},
                                new go.Binding("visible", "visible").makeTwoWay(),
                                $(go.Shape, "RoundedRectangle",
                                    {fill: "#F8F8F8", stroke: null}),
                                $(go.TextBlock, "Yes",
                                    {
                                        textAlign: "center",
                                        font: "10pt helvetica, arial, sans-serif",
                                        stroke: "#333333",
                                        editable: true
                                    },
                                    new go.Binding("text").makeTwoWay())
                            )
                        ),
                        initialContentAlignment: go.Spot.MiddleTop,
                        "ModelChanged": updateAngular,
                        "ChangedSelection": updateSelection,
                        allowDrop: true,
                        "LinkDrawn": showLinkLabel,
                        "LinkRelinked": showLinkLabel,
                        scrollsPageOnFocus: false,
                        allowCopy: true,//不允许在流程里面复制节点
                        // isReadOnly: true,
                        "undoManager.isEnabled": true
                    });
            var lightText = 'whitesmoke';
            scope.mDiagram = diagram;

            //GoJs点击事件
            diagram.addDiagramListener("ObjectSingleClicked", function (e) {
                //scope.clickFun({data: e.subject.part.data});
            });

            //设置节点样式
            function nodeStyle() {
                return [
                    new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
                    {
                        locationSpot: go.Spot.Center,
                        mouseEnter: function (e, obj) {
                            showPorts(obj.part, true);
                        },
                        mouseLeave: function (e, obj) {
                            showPorts(obj.part, false);
                        }
                    }
                ];
            }

            //设置节点上下左右的连接点
            function makePort(name, spot, output, input) {
                return $(go.Shape, "Circle",
                    {
                        fill: "transparent",
                        stroke: null,
                        desiredSize: new go.Size(8, 8),
                        alignment: spot, alignmentFocus: spot,
                        portId: name,
                        fromSpot: spot, toSpot: spot,
                        fromLinkable: output, toLinkable: input,
                        cursor: "pointer"
                    });
            }

            //颜色
            var bluegrad = $(go.Brush, "Linear", {0: "#C4ECFF", 1: "#70D4FF"});

            //模板局部样式
            var actionTemplate = $(go.Panel, "Horizontal",
                $(go.Shape,
                    {width: 12, height: 12},
                    new go.Binding("figure"),
                    new go.Binding("fill")
                ),
                $(go.TextBlock,
                    {font: "10pt Verdana, sans-serif", editable: true},
                    new go.Binding("text").makeTwoWay()
                )
            );

            /**
             * 为节点模板添加自定义的节点样式
             * 类型：长方形可输入文本框
             */
            diagram.nodeTemplateMap.add("",
                $(go.Node, "Spot", nodeStyle(),
                    $(go.Panel, "Auto",
                        $(go.Shape, "Rectangle",
                            {fill: "#edf1f2", stroke: null, minSize: new go.Size(35, 35)},
                            new go.Binding("figure", "figure")
                        ),
                        $(go.TextBlock,
                            {
                                font: "bold 11pt Helvetica, Arial, sans-serif",
                                stroke: '#454545',
                                margin: 8,
                                maxSize: new go.Size(160, NaN),
                                wrap: go.TextBlock.WrapFit,
                                editable: true
                            },
                            new go.Binding("text").makeTwoWay()
                        )
                    ),
                    //设置节点的连接点
                    makePort("T", go.Spot.Top, false, true),
                    makePort("L", go.Spot.Left, true, true),
                    makePort("R", go.Spot.Right, true, true),
                    makePort("B", go.Spot.Bottom, true, false)
                )
            );

            /**
             * 开始节点
             */
            diagram.nodeTemplateMap.add("Start",
                $(go.Node, "Spot", nodeStyle(),
                    $(go.Panel, "Auto",
                        $(go.Shape, "Circle",
                            {minSize: new go.Size(40, 40), fill: "#edf1f2", stroke: null}
                        ),
                        $(go.TextBlock, "Start",
                            {font: "bold 11pt Helvetica, Arial, sans-serif", stroke: '#454545'},
                            new go.Binding("text")
                        )
                    ),
                    makePort("L", go.Spot.Left, true, false),
                    makePort("R", go.Spot.Right, true, false),
                    makePort("B", go.Spot.Bottom, true, false)
                )
            );

            /**
             * 结束节点
             */
            diagram.nodeTemplateMap.add("End",
                $(go.Node, "Spot", nodeStyle(),
                    $(go.Panel, "Auto",
                        $(go.Shape, "Circle",
                            {minSize: new go.Size(40, 40), fill: "#edf1f2", stroke: null}
                        ),
                        $(go.TextBlock, "Start",
                            {font: "bold 11pt Helvetica, Arial, sans-serif", stroke: '#454545'},
                            new go.Binding("text")
                        )
                    ),
                    makePort("T", go.Spot.Top, false, true),
                    makePort("L", go.Spot.Left, false, true),
                    makePort("R", go.Spot.Right, false, true)
                )
            );

            /**
             * comment节点
             */
            diagram.nodeTemplateMap.add("Comment",
                $(go.Node, "Auto", nodeStyle(),
                    $(go.Shape, "File",
                        {fill: "#EFFAB4", stroke: null}
                    ),
                    $(go.TextBlock,
                        {
                            margin: 5,
                            maxSize: new go.Size(200, NaN),
                            wrap: go.TextBlock.WrapFit,
                            textAlign: "center",
                            editable: true,
                            font: "bold 12pt Helvetica, Arial, sans-serif",
                            stroke: '#454545'
                        },
                        new go.Binding("text").makeTwoWay()
                    )
                )
            );

            /**
             * 自定义节点图例
             */
            diagram.nodeTemplateMap.add("formula",
                $(go.Node, "Auto", nodeStyle(),
                    {
                        mouseDragEnter: function (e, grp, prev) {
                            highlightGroup(e, grp, true);
                        },
                        mouseDragLeave: function (e, grp, next) {
                            highlightGroup(e, grp, false);
                        },
                        //mouseDrop: finishDrop,
                    },
                    $(go.Shape, "RoundedRectangle",
                        {
                            fill: "white", stroke: "white", margin: new go.Margin(5, 5, 5, 5),
                        }
                    ),
                    new go.Binding("background", "isHighlighted", function (h) {
                        return h ? "#DC3C00" : "#edf1f2";
                    }).ofObject(),
                    $(go.Panel, "Vertical",
                        {stretch: go.GraphObject.Horizontal, background: "#edf1f2", margin: new go.Margin(5, 5, 5, 5)},
                        new go.Binding("background", "isHighlighted", function (h) {
                            var crtColor = "";
                            var updateColor = "#f7df66", defaultColor = "#edf1f2", flowColor = "#CD96CD", nodeUpdateColor = "#EE6363";
                            switch(h) {
                                case "flow":
                                    crtColor = nodeUpdateColor;
                                    break;
                                case "ADD":
                                    crtColor = nodeUpdateColor;
                                    break;
                                case "isRelate":
                                    crtColor = updateColor;
                                    break;
                                default: 
                                    crtColor = defaultColor;
                            }
                            return crtColor;
                        }).makeTwoWay(),
                        $(go.Panel, "Table",
                            {stretch: go.GraphObject.Horizontal},
                            $(go.TextBlock,
                                {
                                    alignment: go.Spot.Left,
                                    margin: new go.Margin(5, 0, 5, 5),
                                    stroke: "#58666e",
                                    font: "10pt Verdana, sans-serif"
                                },
                                new go.Binding("text", "text").makeTwoWay()
                            )
                        ),
                        $(go.Panel, "Table",
                            {stretch: go.GraphObject.Horizontal},
                            $(go.TextBlock,
                                {
                                    alignment: go.Spot.Left,
                                    margin: new go.Margin(5, 0, 5, 5),
                                    stroke: "#58666e",
                                    font: "8pt Verdana, sans-serif"
                                },
                                new go.Binding("text", "sys").makeTwoWay()
                            ),
                            $("PanelExpanderButton", "COLLAPSIBLE",
                                {column: 1, alignment: go.Spot.Left, margin: new go.Margin(0, 10, 0, 0),}
                            )
                        ),
                        $(go.Panel, "Table",
                            {
                                name: "COLLAPSIBLE",
                                visible: false,     
                                stretch: go.GraphObject.Horizontal,
                                itemTemplate: actionTemplate
                            },
                            $(go.TextBlock, textStyle(),
                                {row: 1, column: 0},
                                new go.Binding("text", "nodeType", function(nodeType) {
                                    return nodeType == "flow" ? "名称：" : "功能点名称：";
                                }).makeTwoWay()
                            ),
                            $(go.TextBlock, textStyle(),
                                {
                                    row: 1, column: 1, columnSpan: 4,
                                    editable: false, isMultiline: false,
                                    minSize: new go.Size(10, 14),
                                    margin: new go.Margin(0, 0, 5, 3)
                                },
                                new go.Binding("text", "relate_name").makeTwoWay()
                            ),
                            $(go.TextBlock, textStyle(),
                                {row: 2, column: 0},
                                new go.Binding("text", "nodeType", function(nodeType) {
                                    return nodeType == "flow" ? "场景：" : "菜单路径：";
                                }).makeTwoWay()
                            ),
                            $(go.TextBlock, textStyle(),
                                {
                                    row: 2, column: 1, columnSpan: 4,
                                    editable: false, isMultiline: false,
                                    minSize: new go.Size(10, 14),
                                    margin: new go.Margin(0, 0, 5, 3)
                                },
                                new go.Binding("text", "relate_path").makeTwoWay()
                            )
                        )
                    ),
                    makePort("T", go.Spot.Top, true, true),
                    makePort("L", go.Spot.Left, true, true),
                    makePort("R", go.Spot.Right, true, true),
                    makePort("B", go.Spot.Bottom, true, true)
                )
            );

            /**
             * 线
             */
            diagram.nodeTemplateMap.add("Line", 
                $(go.Node, "Spot", nodeStyle(),
                    {
                        locationSpot: go.Spot.Center,
                        locationObjectName: "SHAPE",
                        selectionAdorned: false,
                        resizable: true,
                        resizeObjectName: "SHAPE",
                        rotatable: false,
                        rotateObjectName: "SHAPE",
                        layoutConditions: go.Part.LayoutStandard & ~go.Part.LayoutNodeSized
                    },
                    new go.Binding("width", "length").makeTwoWay(),
                    $(go.Shape, { 
                        figure: "LineH",
                        strokeWidth: 5,
                        stroke: "lightcoral",
                        interval: 10
                    },new go.Binding("desiredSize", "size").makeTwoWay())
                )
            );

            go.Shape.defineFigureGenerator("LineH", function (shape, w, h) {
                var geo = new go.Geometry(go.Geometry.Line);
                geo.startX = 0;
                geo.startY = h / 2;
                geo.endX = w;
                geo.endY = h / 2;
                return geo;
            });

            /**
             * 竖线
             */
            diagram.nodeTemplateMap.add("vLine", 
                $(go.Node, "Spot", nodeStyle(),
                    {
                        locationSpot: go.Spot.Center,
                        locationObjectName: "SHAPE",
                        selectionAdorned: false,
                        resizable: true,
                        resizeObjectName: "SHAPE",
                        rotatable: true,
                        rotateObjectName: "SHAPE",
                        layoutConditions: go.Part.LayoutStandard & ~go.Part.LayoutNodeSized
                    },
                    new go.Binding("height", "length").makeTwoWay(),
                    $(go.Shape, { 
                        figure: "LineV",
                        strokeWidth: 5,
                        stroke: "lightcoral",
                        interval: 10
                    })
                )
            );

            go.Shape.defineFigureGenerator("LineV", function (shape, w, h) {
                var geo = new go.Geometry(go.Geometry.Line);
                geo.startX = w / 2;
                geo.startY = 0;
                geo.endX = w / 2;
                geo.endY = h;
                return geo;
            });

            /**
             * user
             */
            diagram.nodeTemplateMap.add("User", 
                $(go.Node, "Spot", nodeStyle(),
                    {
                        locationSpot: go.Spot.Center,
                        locationObjectName: "BpmnTaskUser",
                        selectionAdorned: false,
                        //resizable: true,   //是否允许缩放
                        resizeObjectName: "BpmnTaskUser",
                        //rotatable: true,   //是否允许旋转
                        rotateObjectName: "BpmnTaskUser",
                        layoutConditions: go.Part.LayoutStandard & ~go.Part.LayoutNodeSized
                    },
                    $(go.Panel, "Vertical",  
                        $(go.Shape, "BpmnTaskUser",
                            { alignmentFocus: go.Spot.TopLeft,
                            fill: "#edf1f2",
                            width: 30, height: 30,
                            },
                            new go.Binding("figure", "taskType", nodeActivityTaskTypeConverter)
                        ),
                        $(go.TextBlock,
                            {
                                font: "bold 11pt Helvetica, Arial, sans-serif",
                                margin: new go.Margin(8, 8, 8, 8),
                                maxSize: new go.Size(160, NaN),
                                wrap: go.TextBlock.WrapFit,
                                editable: true
                            },
                            new go.Binding("text").makeTwoWay()
                        )
                    )
                )
            );

            go.Shape.defineFigureGenerator("BpmnTaskUser", function (shape, w, h) {
                var geo = new go.Geometry();
                var fig = new go.PathFigure(0, 0, false);
                geo.add(fig);
                var fig2 = new go.PathFigure(.335 * w, (1 - .555) * h, true);
                geo.add(fig2);
                // Shirt
                fig2.add(new go.PathSegment(go.PathSegment.Line, .335 * w, (1 - .405) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, (1 - .335) * w, (1 - .405) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, (1 - .335) * w, (1 - .555) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Bezier, w, .68 * h, (1 - .12) * w, .46 * h, (1 - .02) * w, .54 * h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, w, h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, 0, h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, 0, .68 * h));
                fig2.add(new go.PathSegment(go.PathSegment.Bezier, .335 * w, (1 - .555) * h, .02 * w, .54 * h, .12 * w, .46 * h));
                // Start of neck
                fig2.add(new go.PathSegment(go.PathSegment.Line, .365 * w, (1 - .595) * h));
                var radiushead = .5 - .285;
                var centerx = .5;
                var centery = radiushead;
                var alpha2 = Math.PI / 4;
                var KAPPA = ((4 * (1 - Math.cos(alpha2))) / (3 * Math.sin(alpha2)));
                var cpOffset = KAPPA * .5;
                var radiusw = radiushead;
                var radiush = radiushead;
                var offsetw = KAPPA * radiusw;
                var offseth = KAPPA * radiush;
                // Circle (head)
                fig2.add(new go.PathSegment(go.PathSegment.Bezier, (centerx - radiusw) * w, centery * h, (centerx - ((offsetw + radiusw) / 2)) * w, (centery + ((radiush + offseth) / 2)) * h, (centerx - radiusw) * w, (centery + offseth) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Bezier, centerx * w, (centery - radiush) * h, (centerx - radiusw) * w, (centery - offseth) * h, (centerx - offsetw) * w, (centery - radiush) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Bezier, (centerx + radiusw) * w, centery * h, (centerx + offsetw) * w, (centery - radiush) * h, (centerx + radiusw) * w, (centery - offseth) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Bezier, (1 - .365) * w, (1 - .595) * h, (centerx + radiusw) * w, (centery + offseth) * h, (centerx + ((offsetw + radiusw) / 2)) * w, (centery + ((radiush + offseth) / 2)) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, (1 - .365) * w, (1 - .595) * h));
                // Neckline
                fig2.add(new go.PathSegment(go.PathSegment.Line, (1 - .335) * w, (1 - .555) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, (1 - .335) * w, (1 - .405) * h));
                fig2.add(new go.PathSegment(go.PathSegment.Line, .335 * w, (1 - .405) * h));
                var fig3 = new go.PathFigure(.2 * w, h, false);
                geo.add(fig3);
                // Arm lines
                fig3.add(new go.PathSegment(go.PathSegment.Line, .2 * w, .8 * h));
                var fig4 = new go.PathFigure(.8 * w, h, false);
                geo.add(fig4);
                fig4.add(new go.PathSegment(go.PathSegment.Line, .8 * w, .8 * h));
                return geo;
            });

            function nodeActivityTaskTypeConverter(s) {
                var tasks = ["BpmnTaskUser"];
                if (s < tasks.length) return tasks[s];
                return "NotAllowed"; // error
            }

            function finishDrop(e, grp) {
                var ok = (grp !== null
                    ? grp.addMembers(grp.diagram.selection, true)
                    : e.diagram.commandHandler.addTopLevelParts(e.diagram.selection, true));
            }

            function highlightGroup(e, grp, show) {
                if (!grp) return;
                e.handled = true;
                if (show) {
                    // var tool = grp.diagram.toolManager.draggingTool;
                    // var map = tool.draggedParts || tool.copiedParts;
                    // if (grp.canAddMembers(map.toKeySet())) {
                    //     grp.isHighlighted = true;
                    //     return;
                    // }
                }
                grp.isHighlighted = false;
            }

            function textStyle() {
                return {font: "9pt sans-serif", stroke: "#58666e"};
            }

            function showPorts(node, show) {
                var diagram = node.diagram;
                if (!diagram || diagram.isReadOnly || !diagram.allowLink) return;
                node.ports.each(function (port) {
                    port.stroke = (show ? "black" : null);
                });
            }

            diagram.linkTemplate = $(go.Link,
                {
                    routing: go.Link.AvoidsNodes,
                    curve: go.Link.JumpOver,
                    corner: 5, toShortLength: 4,
                    relinkableFrom: true,
                    relinkableTo: true,
                    reshapable: true,
                    resegmentable: true,
                    mouseEnter: function (e, link) {
                        link.findObject("HIGHLIGHT").stroke = "rgba(30,144,255,0.2)";
                    },
                    mouseLeave: function (e, link) {
                        link.findObject("HIGHLIGHT").stroke = "transparent";
                    }
                },
                new go.Binding("points").makeTwoWay(),
                $(go.Shape,
                    {isPanelMain: true, strokeWidth: 8, stroke: "transparent", name: "HIGHLIGHT"}
                ),
                $(go.Shape,
                    {isPanelMain: true, stroke: "gray", strokeWidth: 2}
                ),
                $(go.Shape,
                    {toArrow: "standard", stroke: null, fill: "gray"}
                ),
                $(go.Panel, "Auto",
                    {visible: false, name: "LABEL", segmentIndex: 2, segmentFraction: 0.5},
                    $(go.Shape, "RoundedRectangle",
                        {fill: "#F8F8F8", stroke: null}
                    ),
                    $(go.TextBlock, "Yes",
                        {
                            textAlign: "center",
                            font: "10pt helvetica, arial, sans-serif",
                            stroke: "#333333",
                            editable: true
                        },
                        new go.Binding("text").makeTwoWay()
                    ),
                    new go.Binding("visible", "visible").makeTwoWay()
                )
            );

            function updateAngular(e) {
                // if (e.isTransactionFinished) {
                //     scope.$apply();
                // }
            }

            function updateSelection(e) {
                diagram.model.selectedFlowData = null;
                var it = diagram.selection.iterator;
                while (it.next()) {
                    var selnode = it.value;
                    // ignore a selected link or a deleted node
                    if (selnode instanceof go.Node && selnode.data !== null) {
                        if (selnode.data.feature_info) {
                            angular.forEach(config_flow_legend_type, function (type) {
                                if (selnode.data.feature_info.type == type.key) {
                                    selnode.data.feature_info.typeName = type.value;
                                }
                            });
                            selnode.data.sltStatusItem = "";
                            angular.forEach(config_flow_node_status, function (status) {
                                if (selnode.data.status == status.key) {
                                    selnode.data.sltStatusItem = status;
                                }
                            });
                        }
                        if(selnode.data.isFeature) {
                            relateFeature(selnode.data);
                        } else {
                            diagram.model.selectedFlowData = selnode.data;
                        }
                        break;
                    }
                }
                scope.$apply();
            }

            function showLinkLabel(e) {
                var label = e.subject.findObject("LABEL");
                //新建或者修改连线时  把连线的状态设置为add
                e.subject.data.nodeStatus = "add";
                if (label !== null) label.visible = (e.subject.fromNode.data.figure === "Diamond");
                if (e.subject.fromNode.key == '1') {
                    $rootScope.toasterWarningInfo("不能重复链接");
                    diagram.commandHandler.deleteSelection();
                }
            }

            scope.$watch("model", function (newmodel) {
                var oldmodel = diagram.model;
                if (oldmodel !== newmodel) {
                    diagram.removeDiagramListener("ChangedSelection", updateSelection);
                    diagram.model = newmodel;
                    diagram.addDiagramListener("ChangedSelection", updateSelection);
                }
            });

            scope.$watch("model.selectedFlowData.name", function (newname) {
                if (!diagram.model.selectedFlowData) return;
                // disable recursive updates
                diagram.removeModelChangedListener(updateAngular);
                // change the name
                diagram.startTransaction("change name");
                // the data property has already been modified, so setDataProperty would have no effect
                var node = diagram.findNodeForData(diagram.model.selectedFlowData);
                if (node !== null) node.updateTargetBindings("name");
                diagram.commitTransaction("change name");
                // re-enable normal updates
                diagram.addModelChangedListener(updateAngular);
            });

            var palette = $(go.Palette, "myPaletteCompare",
                {
                    scrollsPageOnFocus: false,
                    nodeTemplateMap: diagram.nodeTemplateMap,
                    layout: $(go.GridLayout,
                        {sorting: go.GridLayout.Forward})
                }
            );

            scope.$watch("paModel", function (newmodel) {
                var oldmodel = palette.model;
                if (oldmodel !== newmodel) {
                    palette.model = newmodel;
                }
            });

            scope.diagramD = diagram;
            //监听新拖拽到画布的节点
            diagram.addModelChangedListener(function (evt) {
                // ignore unimportant Transaction events
                if (!evt.isTransactionFinished) return;
                var txn = evt.object;  // a Transaction
                if (txn === null) return;
                // iterate over all of the actual ChangedEvents of the Transaction
                txn.changes.each(function (e) {
                    // ignore any kind of change other than adding/removing a node
                    if (e.modelChange !== "nodeDataArray") return;
                    // record node insertions and removals
                    if (e.change === go.ChangedEvent.Insert) {
                        console.log(evt.propertyName + " added node with key: ");
                        console.log(e.newValue);
                        if (e.newValue.index > 4) {
                            e.newValue.nodeStatus = "add";
                            // } else if (e.change === go.ChangedEvent.Remove) {
                            //     console.log(evt.propertyName + " removed node with key: " + e.oldValue.key);
                        }
                    }
                });
            });

            //监听新拖拽的连线
            diagram.addModelChangedListener(function (evt) {
                // ignore unimportant Transaction events
                if (!evt.isTransactionFinished) return;
                var txn = evt.object;  // a Transaction
                if (txn === null) return;
                // iterate over all of the actual ChangedEvents of the Transaction
                txn.changes.each(function (e) {
                    // record node insertions and removals
                    if (e.change === go.ChangedEvent.Property) {
                        if (e.modelChange === "linkFromKey") {
                            console.log(evt.propertyName + " changed From key of link: " +
                                e.object + " from: " + e.oldValue + " to: " + e.newValue);
                        } else if (e.modelChange === "linkToKey") {
                            console.log(evt.propertyName + " changed To key of link: " +
                                e.object + " from: " + e.oldValue + " to: " + e.newValue);
                        }
                    } else if (e.change === go.ChangedEvent.Insert && e.modelChange === "linkDataArray") {
                        console.log(evt);
                        console.log(evt.propertyName + " added link: " + e.newValue);
                    } else if (e.change === go.ChangedEvent.Remove && e.modelChange === "linkDataArray") {
                        console.log(evt.propertyName + " removed link: " + e.oldValue);
                    }
                });
            });

            //判断当前req关联的feature集合
            function relateFeature(selnodeData) {
                var url = matrix_product_url +"/feature/getAllFeatureForReq?reqId="+ scope.reqId;
                $http.get(url).success(function(result) {
                    if(result.code == "0") {
                        var hasRelate = lodash.findWhere(result.data, {id: selnodeData.feature_id});
                        selnodeData.hasRelateFeature = hasRelate != undefined ? true : false;
                        diagram.model.selectedFlowData = selnodeData;
                    } else {
                        $rootScope.toasterErrorInfo(result.desc);
                    }
                });
            };
        }
    };
});